\chapter{Кросс-компиляция и отладка}
\section{Tеоретические сведения}
В данной лабораторной работе предлагается, воспользовавшись IDE Momentics для QNX,
получить исполняемые файлы для ОС QNX, выполняя процесс сборки под Windows. 
QNX при этом является целевой (target) платформой, Windows -- инструментальной (host).

\begin{figure}[h]
\center{\includegraphics[width=1.\linewidth]{debug_remote}}
\caption{Удаленная отладка}
\end{figure}

Для запуска QNX необходимо использовать vmplayer, распространяемый бесплатно, либо
Virtual Box. Они установлены на учебных компьютерах.

Кроме того, вам потребуется образ QNX. На учебных компьютерах он распространяется 
в виде готового диска виртуальной машины, на котором находится уже установленный
QNX. Для выполнения лабораторных работ дома потребуется установить vmplayer
и QNX самостоятельно.

\section{Замечания по работе в лабораторном классе}
Пункт \ref{sub:install} не относится к работе в лабораторном классе. В нем вам будет
предоставлена уже функционирующая виртуальная машина QNX.

\section{Установка QNX на виртуальную машину}
\label{sub:install}
Виртуальная машина создает среду выполнения, эмулирующую оборудование компьютера,
для конкретной программы (в частности, операционной системы). Получается своего
рода <<компьютер в компьютере>>.

Рассмотрим установку QNX самостоятельно на примере vmplayer 5.0 (вы можете 
воспользоваться любой удобной виртуальной машиной).

\begin{enumerate}
\itemИз меню Player выбрать пункт File->New Virtual Machine.

\itemДалее следует выбрать диск, с которого будет производиться установка 
(рис. ~\ref{ris:vm_iso_cd}).

\begin{figure}[pH]
\center{\includegraphics[width=.5\linewidth]{vm_iso_cd}}
\caption{Выбор источника установки}
\label{ris:vm_iso_cd}
\end{figure}

Если у вас имеется CD-диск, следует выбрать 1-ый пункт, в противном случае-
указать, где находится его образ (файл .iso). Переходим к следующему экрану
(Next).

\itemДанное меню несущественно. Достаточно выбрать Other/Other.
(рис. ~\ref{ris:vm_other}).

\begin{figure}[pH]
\center{\includegraphics[width=.5\linewidth]{vm_other}}
\label{ris:vm_other}
\caption{Выбор типа ОС}
\end{figure}

\itemВ данном меню следует выбрать имя ВМ и папку для хранения служебных файлов
(на ваше усмотрение) (рис. ~\ref{ris:vm_name}).

\begin{figure}[pH]
\center{\includegraphics[width=.5\linewidth]{vm_name}}
\caption{Выбор папки для ВМ}
\label{ris:vm_name}
\end{figure}

\itemСледующий пункт содержит меню выбора размера \textit{виртуального} жестого
диска -- максимально возможный. Фактический размер заполняется по мере записи
данных на этот диск. Можно оставить значение по умолчанию.

\itemВ следующем пункте достаточно нажать Finish.

\itemТеперь в вашем распоряжении находится сконфигурированная виртуальная машина.
Осталось только ее запустить и произвести инсталляцию QNX, как на обычный 
компьютер.
(рис. ~\ref{ris:vm}).

\begin{figure}[pH]
\center{\includegraphics[width=.5\linewidth]{vm}}
\caption{Вид окна VM Player}
\label{ris:vm}
\end{figure}

\itemВ начале установки следует, прежде всего, дать возможность виртуальной машине
<<захватить>> курсор. Для этого его достаточно перевести в окно виртуальной машины.
Чтобы <<освободить>> его необходимо нажать Ctrl+Alt.

\itemДля установки в первом экране установщика QNX следует выбрать F3 (Press F3
to install into local drive).

\itemВо втором экране -- F1 (Press to continue).

\itemВ процессе установки вам будет предложено ввести серийный номер, который
вы получили при регистрации на www.qnx.com, указав тип лицензии как <<Академическая
для некоммерческого использования>>.

\itemДалее достаточно принимать условия по умолчанию, нажимая в каждом экране F1.
Для настройки дополнительных опций следует обратиться к содержанию текста на экране.

\itemВ конце копирования установочных файлов инсталлятор предложит директорию
для служебных программ (/usr/qnx641), следует нажать y. Далее -- снова y. 

\itemДалее следует дождаться окончания установки (5-15 минут), после чего
инсталлятор предложит перезагрузить компьютер (Press Enter to reboot...),
что и следует сделать.

\end{enumerate}

\section{Работа в Momentics IDE}
Momentics IDE базируется на Eclipse и в части работы с проектами и компиляции
вам уже знакома.

В нашем случае потребуется компилировать из него программы под QNX, а не под 
Windows, как в первой лабораторной работе.

Базовые действия по созданию пустого приложения под QNX средствами Momentics:
\begin{enumerate}
\itemОткрыть QNX Momentics IDE. При этом, как и в работе с Eclipse под Windows,
следует выбрать рабочую папку (workspace).
\itemДалее -- File->New->QNX C Project. (рис. ~\ref{ris:qnx_proj}).
\begin{figure}[pH]
\center{\includegraphics[width=.5\linewidth]{qnx_proj}}
\caption{Создание проекта для QNX}
\label{ris:qnx_proj}
\end{figure}

\itemСущественным вариантом является выбор варианта сборки в следующем меню
QNX C/C++ Project Settings. В данном окне следует выбрать вкладку Build
Variants и в ней -- X86 -- Debug. Это означает, что мы собираем исключительно
для платформы X86 (процессоры, совместимые с Intel Pentium, Celeron).
(рис. ~\ref{ris:build}).

\begin{figure}[pH]
\center{\includegraphics[width=.5\linewidth]{build}}
\caption{Варианты сборки}
\label{ris:build}
\end{figure}

\itemПосле выбора варианта сборки следует нажать Finish. 
\itemПеред вами откроется редактор с текстом программы, содержащей 
функцию main.
\itemСборка данной программы осуществляется из меню Project->Build All
(аналогично первой лабораторной работе).
\itemПосле сборки в Project Explorer в папке вашего проекта появится
вкладка Binaries, открыв которую можно увидеть появившийся исполняемый
файл (например, examp1\_g). Постфикс g означает, что данный файл собран
с отладочной информацией.

\end{enumerate}

\section{Взаимодействие между QNX и Momentics IDE}

\subsection{Настройка VM Player}
Если QNX запущен на виртуальной машине, прежде всего следует настроить сеть между QNX и Windows.
Для этого в меню VM Player -> Manage -> Virtual Machine Settings следует выбрать Network Adapter.
В нем следует определить тип подключения, которое будет поддерживать виртуальной сетевой картой.
В нашем случае проще всего выбрать Host only Network, впрочем, в случае, если вы хотите предоставить
QNX доступ к Интернет, следует выбрать NAT.

Далее предполагается, что выбран Host Only Network.

\subsection{Настройка целевой машины}

Прежде всего, необходимо запустить на целевой машине qconn. Эта программа предоставляет доступ 
к удаленным компонентам IDE, таким как просмотр и правка содержимого файловой системы QNX, информации 
о системе, обмен файлами.  Qconn – консольная программа. Она имеет следующие необязательные 
параметры командной строки:

\begin{lstlisting}
qconn [-v] [port=portnum][qconn_prio=qpriority][child_prio=cpriority]
\end{lstlisting}
\begin{itemize}
\item -v отображает версию, а затем выходит.
\item port=знаение – порт TCP/IP, к которому можно обратиться с инструментальной машины. По умолчанию – 8000.
\item qconn\_prio – приоритет, с которым запускается qconn. Полезен в случае «зависания» целевой машины, 
когда к ней невозможно присоединиться из IDE. Задав высокий приоритет можно «задавить» программы, запущенные в QNX. По умолчанию – 10.
\item child\_prio – приоритет программ, запускаемых удаленно с инструментальной машины. По умолчанию – 10.
\end{itemize}
В общем случае достаточно в терминале из под root ввести команду qconn:
\begin{lstlisting}
root# qconn
\end{lstlisting}

При этом она сама перейдет в фоновый режим.
Кроме того, удобно прописать ее запуск в /etc/rc.d/rc.local, который запускается при 
загрузке системы.

\begin{lstlisting}
root# echo qconn >> /etc/rc.d/rc.local
\end{lstlisting}

(команда в терминале, обозначающая дозапись в файл строчки qconn; можно воспользоваться 
текстовым редактором на ваш вкус).

Кроме того, необходимо узнать IP целевой машины. Для этого в терминале следует ввести ifconfig 
и найти строчку inet: <ip> в секции en0:

\begin{lstlisting}
en0: flags = ...
   ...
   inet <ip> network ...
\end{lstlisting}

\subsection{Настройки в IDE Momentics для запуска и отладки программ под QNX}

Со стороны IDE необходимо задать целевую машину, на которой будут запускаться 
откомпилированные под QNX программы. Для этого необходимо:

\begin{itemize}
\itemИз меню выбрать File -> New -> Other
\itemВ выпадающем списке -- QNX.
\itemДалее -- QNX Target System Project.
\itemНажать Next.
\itemВвести имя цели и IP машины, на которой в той же подсети, что и инструментальная, 
запущена целевая под управлением QNX.
\end{itemize}
 
Далее необходимо создать <<Конфигурацию запуска>>, то есть указать IDE сценарий загрузки 
и выполнения файла на целевую машину. При этом, следует отметить, что именно происходит 
при запуске бинарного файла, скомпилированного под QNX, из IDE Momentics. Указанный 
в конфигурации файл записывается по протоколу QNET на целевую машину, далее он запускается 
на выполнение, а консольный вывод и интерфейс отладки передается инструментальной машине.

Итак, для создания конфигурации запуска:
\begin{itemize}
\item В окне Project Explorer, разверните пункт Binaries.
\item Нажмите правой кнопкой мышки на исполняемом файле.
\item Выберите Run As >  C/C++ QNX Application .
\item Задайте имя конфигурации (если потребуется). 
\item В панели Target Options выберите целевую машину (если потребуется).
\item Нажмите Run.
\end{itemize}

Обратите внимание, что консольный ввод-вывод программы перенаправится во вкладку Console
IDE, расположенную в нижней части экрана.
 
\begin{scriptsize}
В том же окне можно задать также аргументы командной строки на вкладке Arguments, а также выбрать 
папку для загрузки в Upload. 

Конфигураций в Workspace может быть достаточно много, и гибкое варьирование 
их позволит переключаться между различыми бинарными файлами и их параметрами запуска.
\end{scriptsize}

Кроме конфигураций запуска возможно использование отладочной конфигурации. Для этого вместо пункта 
Run необходимо выбрать Debug. Окно настроек аналогично Run, только при отладке происходит 
переключение визуальных режимов IDE (из С/С++ Perspective в Debug), аналогично 
работе в Eclipse под Windows.
 
\section{Пояснения: имитация одномерных и многомерных массивов произвольного
размера с помощью указателей}

Ниже приведен пример программ, имитирующих двумерный и одномерный массив с помощью указателей.

\begin{lstlisting}
#include <stdio.h>
#include <stdlib.h>

#define LENGTH 10

int main(int argn, char* argv[]) {
  int* pi;
  int i;

  pi = calloc(sizeof(int), LENGTH);

  for(i = 0; i < LENGTH; ++i)
    pi[i] = i;

  for(i = 0; i < 10; ++i)
    printf("[%d] %d\n", i, pi[i]);

  return 0;
}
\end{lstlisting}

В данной программе имитируется работа с одномерным массивом размерности 10.
Результат работы программы:

\begin{lstlisting}
[0] 0
[1] 1
...
[9] 9
\end{lstlisting}

Аналогично можно имитировать работу с двумерным массивом. В примере ниже
вначале выделяется "массив" указателей на int из трех указателей, затем
каждый из указателей инициализируется "массивом" из трех int. Таким образом
можно имитировать работу с матрицей 3x3 и произвольной размерности.

\begin{lstlisting}
#include <stdio.h>
#include <stdlib.h>

#define DIM1 3
#define DIM2 3

int main(int argn, char* argv[]) {
  int** ppi;
  int i, j;

  ppi = calloc(sizeof(int*), DIM1);
  for(i = 0; i < DIM2; ++i)
    ppi[i] = calloc(sizeof(int), 3);

  for(i = 0; i < DIM1; ++i) 
    for(j = 0; j < DIM2; ++j)
      ppi[i][j] = i + j;

  for(i = 0; i < 3; ++i) 
    for(j = 0; j < 3; ++j)
      printf("[%d][%d] %d\n", i, j, ppi[i][j]);

  return 0;
}
\end{lstlisting}

Вывод программы:
\begin{lstlisting}
[0][0] 0
[0][1] 1
[0][2] 2
[1][0] 1
[1][1] 2
[1][2] 3
[2][0] 2
[2][1] 3
[2][2] 4
\end{lstlisting}


\section{Индивидуальное задание}

\begin{enumerate}
\itemВ соответствии с индивидуальными заданияим первой лабораторной работы следует 
откомпилировать написанную в ней программу под QNX, а также добиться запуска 
и выполнения ее в виртуальной машине. При необходимости следует 
воспользоваться отладчиком.

\itemДалее вам предлагается модифицировать вашу программу таким образом, чтобы
она могла работать с массивами переменной длины или, соответственно,
матрицами произвольной размерности. 

Функции для работы с одномерными массивами в этом случае будут иметь
следующую сигнатуру:

\begin{lstlisting}
int find_min(int* array, int num);
int find_max(int* array, int num);
\end{lstlisting}

Для работы с двумерными:
\begin{lstlisting}
int find_min(int** array, int num);
int find_max(int** array, int num);
\end{lstlisting}

%\textbf{
%В начале работы программы размерность должна быть введена с клавиатуры,
%будучи сопровождена соответствующим приглашением ввода.
%}

\end{enumerate}
